package com.jyh.blog.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jyh.blog.dao.*;
import com.jyh.blog.dto.*;
import com.jyh.blog.entity.Article;
import com.jyh.blog.entity.WebsiteConfig;
import com.jyh.blog.service.*;
import com.jyh.blog.utils.BeanCopyUtils;
import com.jyh.blog.utils.IpUtils;
import com.jyh.blog.vo.BlogInfoVO;
import com.jyh.blog.vo.PageVO;
import com.jyh.blog.vo.WebsiteConfigVO;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

import static com.jyh.blog.constant.CommonConst.*;
import static com.jyh.blog.constant.RedisPrefixConst.*;
import static com.jyh.blog.enums.ArticleStatusEnum.PUBLIC;

@Service
public class BlogInfoServiceImpl implements BlogInfoService {
    @Autowired
    private WebsiteConfigService websiteConfigService;
    @Autowired
    private CommentDao commentDao;
    @Autowired
    private UserInfoDao userInfoDao;
    @Autowired
    private ArticleDao articleDao;
    @Autowired
    private CategoryDao categoryDao;
    @Autowired
    private TagDao tagDao;
    @Autowired
    private UniqueViewService uniqueViewService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private PageService pageService;
    @Autowired
    private HttpServletRequest request;

    @Override
    public WebsiteConfigVO getWebSiteConfig() {
        WebsiteConfigVO websiteConfigVO;
        // 获取缓存数据
        Object websiteConfig = redisService.get(WEBSITE_CONFIG);
        if (Objects.nonNull(websiteConfig)) {
            websiteConfigVO = JSON.parseObject(websiteConfig.toString(), WebsiteConfigVO.class);
        } else {
            // 从数据库中加载
            String config = websiteConfigService.getById(DEFAULT_CONFIG_ID).getConfig();
            websiteConfigVO = JSON.parseObject(config, WebsiteConfigVO.class);
            redisService.set(WEBSITE_CONFIG, config);
        }
        return websiteConfigVO;
    }

    @Override
    public void updateWebSiteConfig(WebsiteConfigVO websiteConfigVO) {
        String config = JSON.toJSONString(websiteConfigVO);
        WebsiteConfig websiteConfig = WebsiteConfig.builder()
                .id(DEFAULT_CONFIG_ID)
                .config(config)
                .build();
        websiteConfigService.updateById(websiteConfig);
        //redis中删除
        redisService.del(WEBSITE_CONFIG);
    }

    //后台首页信息
    @Override
    public BlogBackInfoDTO getBlogBackInfo() {
        //访问量
        Object count = redisService.get(BLOG_VIEWS_COUNT);
        Integer viewsCount = Integer.parseInt(Optional.of(count).orElse(0).toString());
        //评论量
        Integer commentNum = commentDao.selectCount(null);
        //用户量
        Integer userNum = userInfoDao.selectCount(null);
        //文章量
        Integer articleNum = articleDao.selectCount(null);
        //分类统计
        List<CategoryDTO> categoryDTOList = categoryDao.categoryList();
        //标签列表
        List<TagDTO> tagDTOList = BeanCopyUtils.copyList(tagDao.selectList(null), TagDTO.class);
        //文章统计列表
        List<ArticleStatisticsDTO> statisticArticleList = articleDao.statisticArticleList();
        //一周用户量集合
        List<UniqueViewDTO> uniqueViewDTOList = uniqueViewService.statisticUniqueViewList();
        //阅读量前五的文章
        Map<Object, Double> articleViewMap = redisService.zReverseRangeWithScore(ARTICLE_VIEWS_COUNT, 0, 4);
        BlogBackInfoDTO backInfoDTO = BlogBackInfoDTO.builder()
                .viewsCount(viewsCount)
                .commentNum(commentNum)
                .userCount(userNum)
                .articleCount(articleNum)
                .categoryDTOList(categoryDTOList)
                .tagDTOList(tagDTOList)
                .articleStatisticsList(statisticArticleList)
                .uniqueViewDTOList(uniqueViewDTOList)
                .build();
        if (!CollectionUtils.isEmpty(articleViewMap)) {
            List<ArticleRankDTO> articleRankDTO = rankArticleList(articleViewMap);
            backInfoDTO.setArticleRankDTOList(articleRankDTO);
        }
        return backInfoDTO;
    }

    /**
     * 阅读量前五文章排序
     * map转换list
     *
     * @param articleViewMap
     * @return
     */
    private List<ArticleRankDTO> rankArticleList(Map<Object, Double> articleViewMap) {
        //提前文章id
        List<String> idList = new ArrayList<>(articleViewMap.size());
        articleViewMap.forEach((k, v) -> idList.add(k.toString()));
        //查询数据库后封装
        return articleDao.selectList(new LambdaQueryWrapper<Article>()
                .select(Article::getId, Article::getTitle)
                .in(Article::getId, idList))
                .stream().map(item -> ArticleRankDTO.builder()
                        .articleTitle(item.getTitle())
                        .viewsCount(articleViewMap.get(item.getId()).intValue())
                        .build())
                .sorted(Comparator.comparingInt(ArticleRankDTO::getViewsCount).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public BlogHomeInfoDTO getBlogHoneInfo() {
        //文章数量
        Integer articleNum = articleDao.selectCount(new LambdaQueryWrapper<Article>()
                .eq(Article::getStatus, PUBLIC.getStatus())
                .eq(Article::getIsDelete, FALSE)
        );
        //分类数量
        Integer categoryNum = categoryDao.selectCount(null);
        //标签数量
        Integer tagNum = tagDao.selectCount(null);
        //访问量
        Object count = redisService.get(BLOG_VIEWS_COUNT);
        String viewNum = Optional.ofNullable(count).orElse(0).toString();
        //网站配置
        WebsiteConfigVO webSiteConfig = this.getWebSiteConfig();
        //页面
        List<PageVO> pageList = pageService.pageList();
        return BlogHomeInfoDTO.builder()
                .articleCount(articleNum)
                .categoryCount(categoryNum)
                .tagCount(tagNum)
                .viewsCount(viewNum)
                .websiteConfig(webSiteConfig)
                .pageList(pageList)
                .build();
    }

    @Override
    public void report() {
        //ip地址
        String ipAddress = IpUtils.getIpAddress(request);
        //浏览器信息
        UserAgent userAgent = IpUtils.getUserAgent(request);
        Browser browser = userAgent.getBrowser();
        OperatingSystem os = userAgent.getOperatingSystem();
        //用户唯一标识
        String uuid = ipAddress + browser.getName() + os.getName();
        String md5 = DigestUtils.md5DigestAsHex(uuid.getBytes());
        //未访问
        if (!redisService.sIsMember(UNIQUE_VISITOR, md5)) {
            String ipSource = IpUtils.getIpSource(ipAddress);
            //统计游客地域分布
            if (StringUtils.isNotBlank(ipSource)) {
                //能查到ip归属地址
                String user_area = ipSource.substring(0, 2)
                        .replace(PROVINCE, "")
                        .replace(CITY, "");
                redisService.hIncr(VISITOR_AREA, user_area, 1L);
            } else {
                redisService.hIncr(VISITOR_AREA, UNKNOWN, 1L);
            }
            //浏览量 + 1
            redisService.incr(BLOG_VIEWS_COUNT, 1L);
            //保存访问设备
            redisService.sAdd(UNIQUE_VISITOR, md5);
        }

    }

    @Override
    public void updateAbout(BlogInfoVO blogInfoVO) {
        String aboutContent = blogInfoVO.getAboutContent();
        redisService.set(ABOUT, aboutContent);
    }

    @Override
    public String getAbout() {
        Object aboutContent = redisService.get(ABOUT);
        return Objects.nonNull(aboutContent) ? aboutContent.toString() : "";
    }
}
